Skip to content

Speculative Decoding ​

标签
AI/infra/推理引擎
AI/infra/解码优化
字数
2634 字
阅读时间
11 分钟

自回归解码是串行的 —— 第 t+1 个 token 必须等第 t 个算完(见 03-Decoder-Only 与自回归)。Speculative Decoding 用「先猜后验」打破这个串行瓶颈:一次前向产出多个 token,且输出分布与逐 token 采样完全相同。

它做的事和前面所有优化都不同:不减访存,而是让同一次访存产出更多结果。

为什么能加速:一次套利 ​

回顾 01-推理性能指标与瓶颈定位 的结论:Decode 每步只处理 1 个 token,却要把整个模型权重从 HBM 流一遍 —— 算术强度约 1–2 FLOP/Byte。

对比硬件的 ridge point(峰值算力 ÷ 峰值带宽):

卡精度峰值算力带宽Ridge
H100 SXMFP16989 TFLOPS3.35 TB/s295 FLOP/Byte
H100 SXMFP81,979 TFLOPS3.35 TB/s591 FLOP/Byte
H200FP81,979 TFLOPS4.8 TB/s412 FLOP/Byte
B200FP8约 4,500 TFLOPS8 TB/s562 FLOP/Byte

单流 Decode 的工作点是 1–2 FLOP/Byte,比 ridge 低两到三个数量级。

这个比值就是 speculation budget —— 在撞上带宽天花板之前,你还能往每次搬运里塞多少计算。单流上它大约是 300–600×。

这就是 Speculative Decoding 的套利空间:既然算力闲置了两三个数量级,那就用计算换串行步数 —— 让目标模型一次前向同时验证多个候选 token。

无损的机制:拒绝采样 ​

设目标模型分布 p(x)、草稿模型分布 q(x)。每轮:

  1. 草稿模型自回归提出 K 个候选 token:x1,…,xK∼q
  2. 目标模型对全部 K+1 个位置做一次并行前向,得到每个位置的 p
  3. 从左到右逐个接受/拒绝

接受规则:

Paccept(x)=min(1,p(x)q(x))
  • 若 p(x)≥q(x) → 必然接受(草稿低估了它,没有理由拒绝)
  • 若 p(x)<q(x) → 以 p(x)/q(x) 的概率接受

拒绝时的补救:丢弃该 token,从修正后的残差分布重新采样:

Residual(x)=max(0, p(x)−q(x))∑ymax(0, p(y)−q(y))

接受与修正的数学刚好配平 —— 最终输出分布与「直接从目标模型逐个采样」完全相同,在所有温度设置下都成立。

换成一句话:用户从输出上分辨不出用了投机解码。 这不是近似加速,是精确加速。

一个必须说清的 caveat ​

losslessness 只对「精确的拒绝采样规则」成立

工程上有更快的变体 —— relaxed acceptance、typical acceptance、各种激进的树接受策略 —— 它们靠放松检验来抬高接受率,这些会改变输出分布。

它们往往值得用,但引用加速比时必须说明是哪种规则产生的。一个来自放松接受的 4× 和一个来自精确拒绝采样的 4×,不是同一种东西。

一轮投机解码的完整流程:

  ① 草稿模型自回归提出 K 个候选:x₁, x₂, …, x_K ~ q

  ② 目标模型对全部 K+1 个位置做**一次并行前向** ⇒ 得到每个位置的 p

  ③ 从左到右逐个接受 / 拒绝

       ├─ p(xₖ) ≥ q(xₖ) ⇒ 必然接受(草稿低估了它,没有理由拒绝)
       │
       └─ p(xₖ) < q(xₖ) ⇒ 以 p(xₖ)/q(xₖ) 的概率接受
                            │
                            └─ 拒绝 ⇒ 丢弃该 token,从残差分布重新采一个:
                                 Res(x) = max(0, p(x) − q(x)) / Σ_y max(0, p(y) − q(y))

  ⇒ 接受与修正的数学刚好配平 ⇒ 最终输出分布与「直接从目标模型逐个采样」完全相同
  ⇒ 用户从输出上分辨不出用了投机解码 —— 这是精确加速,不是近似

  注意:这个无损性只对「精确的拒绝采样规则」成立。relaxed acceptance、
  typical acceptance 这类变体靠放松检验抬高接受率,会改变输出分布 ——
  引用加速比时必须说明是哪种规则产生的。

核心判据:看 accept length,不看接受率 ​

加速比由「每轮平均接受多少个 token」决定,不是由接受率决定。

一个「下一步 90% 对、但第三步就崩」的草稿,不如一个「70% 对、但能连贯五步」的草稿。

原因是经济结构:每一轮 run 无论多长,都恰好付一次目标模型的权重加载。所以杠杆在 run 的长度:

加速比≈平均接受长度+11×11+草稿开销占比

「+1」是目标模型在整条都接受时会额外给出的那个 bonus token。

这条判据决定了所有后续优化的方向 —— 从「找小模型」转向「让草稿在长距离上与目标对齐」。

演进脉络 ​

阶段方案做法报告加速
前身(2018)Blockwise Parallel Decoding辅助预测头猜多个未来 token只支持贪心解码,不保持采样分布
原始(2022–23)Leviathan(arXiv:2211.17192,ICML 2023 oral)/ Chen(arXiv:2302.01318)独立小模型做草稿 + 修正拒绝采样T5-XXL 2–3×;Chinchilla 2–2.5×
树验证SpecInfer(ASPLOS 2024)多个小模型联合建候选树,目标一次并行验证整棵树,保留最长有效路径1.5–3.5×
去草稿模型Medusa(arXiv:2401.10774)不另设草稿模型,在目标模型上挂多个轻量解码头,各预测一个未来位置2.2–3.6×
特征空间草稿EAGLE在目标的内部特征(倒数第二层)上做自回归,而非 token 上LLaMA-2-Chat-70B 延迟降 2.7–3.5×
动态树EAGLE-2(ICML 2024)树形动态伸缩:不确定处展宽、确定处保持窄—
训练对齐EAGLE-3(NeurIPS 2025,arXiv:2503.01840)融合早/中/晚层特征、直接预测 token(去掉特征回归中间步)、动态 draft tree接受率 0.75→0.82,每轮验证 token 数 3.0→4.5
终点Multi-Token Prediction(DeepSeek 等)把草稿折进目标模型本身—

方向很清晰:从「维护两个模型」→「把草稿折进目标」,代价与收益都在这一条线上移动。

Tree Attention 验证 ​

草稿输出一棵树时,目标模型仍只做一次前向:

用 tree attention mask 代替纯线性的因果掩码 —— 每个 token 只 attend 它在树上的祖先。

因果掩码的「下三角」被替换成「树拓扑」,其余机制不变。所以一次前向能验证多条候选路径,取最长可接受的分支。这是「一次验证多个候选」的具体实现方式。

树验证:因果掩码换成树拓扑

  普通因果掩码(下三角)

        x₁  x₂  x₃  x₄
   x₁   ▣   ·   ·   ·
   x₂   ▣   ▣   ·   ·
   x₃   ▣   ▣   ▣   ·
   x₄   ▣   ▣   ▣   ▣

  树注意力掩码:每个 token 只 attend 它在树上的祖先

                 x₁(根)
                ╱   │   ╲
              x₂   x₃   x₄
              │    │
              x₅   x₆

        x₁  [▣ · · · · ·]
        x₂  [▣ ▣ · · · ·]
        x₃  [▣ · ▣ · · ·]
        x₄  [▣ · · ▣ · ·]
        x₅  [▣ ▣ · · ▣ ·]
        x₆  [▣ · ▣ · · ▣]      ← 只点亮「自己 + 祖先」那几格

  ⇒ 因果掩码的「下三角」被替换成「树拓扑」,其余机制不变
  ⇒ 于是一次前向能验证多条候选路径,取最长可接受的分支

草稿模型怎么训 ​

用随机的小模型当草稿,效果很差。 标准做法是从目标模型蒸馏:

步做法
1选一个小架构 —— 70B 目标配约 1B 草稿,7B 目标配约 500M(小 5–30×)
2用目标模型跑一遍大语料,存下它的 next-token 分布
3用 KL 散度对齐目标的分布训练草稿 —— 不是用真值 token

关键在第三步:用真值训出来的草稿「猜的是人写什么」,而它要猜的是「目标模型会输出什么」—— 这两者不一样。

蒸馏后的接受率经验值:

场景接受率 α
代码0.6 – 0.8
自然语言对话0.7 – 0.85

生产环境对应的加速比落在 2–3×。

工程上的两个约束 ​

与调度的耦合 ​

投机解码在 V1 调度器里表示为「某个请求这一步要处理多少 token」的一个取值(见 03-推理调度:Continuous Batching 与 Chunked Prefill):每轮验证是若干个候选 token。

代价是一步内不同请求推进的 token 数不再统一,KV 块的增长也不再是每步一块 —— 这抬高了调度的复杂度,与 前缀缓存 叠加时还要处理更复杂的块对齐。

与量化的叠加风险 ​

草稿与目标都量化时,两者的分布偏移会叠加,接受率下降得更快。收益可能不如预期(见 08-量化)。

什么时候值得用 ​

判据是任务的「可预测性」:

场景预期
代码生成加速明显 —— 语法与惯用法高度重复,草稿容易猜对
结构化输出 / 翻译加速明显
开放对话 / 创意写作收益有限 —— 下一步本来就不确定,草稿猜不中
温度很低的采样加速明显(接近贪心时草稿更容易对齐)
高温度采样收益下降

生产采用现状:2024 年起成为标准配置。Google 用在搜索的 AI Overviews;vLLM、TensorRT-LLM、SGLang 均内置支持。

相关 ​

参考 ​

贡献者 ​

文件历史 ​